#include "ssd1306.h"

#include <stdio.h>
#include <stdint.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "wifiiot_errno.h"
#include "wifiiot_i2c.h"
#include "wifiiot_i2c_ex.h"

#include "gramBitMap.h"

// 定义设备宽高
#ifndef SSD1306_W
#define SSD1306_W (128)
#endif

#ifndef SSD1306_H
#define SSD1306_H (64)
#endif

// 总线选择
#ifndef SSD1306_HOST	
#define SSD1306_HOST    WIFI_IOT_I2C_IDX_1
#endif

// 设备地址
#ifndef SSD1306_ADDR
#define SSD1306_ADDR	(0x78)
#endif

// 总线选择
static WifiIotI2cIdx _i2cIdx = SSD1306_HOST;

//显示缓存
// 这里多一个字节,用于"写数据“指令,可以节省一次内存拷贝操作
static unsigned char OLED_GRAM[(SSD1306_W * SSD1306_H / 8) + 1];

// ssd1306操作结构体
static _SSD1306 ssd1306;// = {SSD1306_W, SSD1306_H, &Font_8x16};//ssd1306操作结构体

// 复位
static void SSD1306Reset(void)
{
	return;
}

// 写指令
static void SSD1306WriteCmd(unsigned char cmd)
{
    unsigned int ret;
    uint8_t send_data[2] = { 0x00, cmd };// 0x00:指令 

	WifiIotI2cData sht3x_i2c_data = { 0 };
    sht3x_i2c_data.sendBuf = send_data;
    sht3x_i2c_data.sendLen = 2;
    
    // 传输数据
    ret = I2cWrite(_i2cIdx, SSD1306_ADDR, &sht3x_i2c_data);
    if (ret != 0)
    {
        printf("ssd1306_write_cmd %x, ret %u.\r\n", cmd, ret);
    }
}

// 写数据
static void SSD1306WriteData(unsigned char *data, unsigned int size)
{
	unsigned int ret;

    data[0] = 0x40;// 写数据
    
	WifiIotI2cData sht3x_i2c_data = { 0 };
    sht3x_i2c_data.sendBuf = data;
    sht3x_i2c_data.sendLen = size;

    // 传输数据
    ret = I2cWrite(_i2cIdx, SSD1306_ADDR, &sht3x_i2c_data);
    if (ret != 0)
    {
        printf("ssd1306_write_data, ret %u.\r\n", ret);
    }
}

//设置当前字体
void SSD1306SetFont(_FontDef *Font)
{
	ssd1306.cFont = Font;
}

//刷新数据
void SSD1306RefreshGram(void)
{
	SSD1306WriteCmd(0x21);    	//设置列起始值与终止值
	SSD1306WriteCmd(0x00);      	
	SSD1306WriteCmd(0x7F);      	  
	SSD1306WriteCmd(0x22);		//设置行起始值与终止值
	SSD1306WriteCmd(0x00);
	SSD1306WriteCmd(0x07);
	
	SSD1306WriteData(OLED_GRAM, (SSD1306_W * SSD1306_H/8) + 1);
}

//清屏函数	  
void SSD1306Clear(void) 
{
	int i;
	for(i = 0; i < 8 * 128; i++) OLED_GRAM[i] = 0X00;
}		

// 打印一个字符
void SSD1306DrawChar(int x, int y, unsigned char ch)
{
	BitMapDrawChar(OLED_GRAM + 1, x, y, ch, ssd1306.cFont);
}

// 打印字符串
void SSD1306DrawString(int x, int y, const char *str)
{
	int xIndex;

	xIndex = x;
	while(*str >= ' ' && *str <= '~')
	{
		BitMapDrawChar(OLED_GRAM + 1, xIndex, y, *str, ssd1306.cFont);
		
		xIndex += ssd1306.cFont->FontWidth;
		str++;
	}
}

// 初始化配置
void SSD1306InitCfg(_FontDef *Font)
{
	if (NULL == Font) return;

	// 设置字体
	ssd1306.cFont = Font;
	ssd1306.Width = SSD1306_W;
	ssd1306.Height = SSD1306_H;

    SSD1306Reset();// 复位设备

	SSD1306WriteCmd(0xAE); //关闭显示
	
	SSD1306WriteCmd(0xD5); //设置时钟分频因子,震荡频率
	SSD1306WriteCmd(0x80);   //[3:0],分频因子;[7:4],震荡频率
	SSD1306WriteCmd(0xA8); //设置驱动路数
	SSD1306WriteCmd(0X3F); //默认0X3F(1/64) 
	
	SSD1306WriteCmd(0xD3); //设置显示偏移
	SSD1306WriteCmd(0X00); //默认为0

	SSD1306WriteCmd(0x40); //设置显示开始行 [5:0],行数.
													    
	SSD1306WriteCmd(0x8D); //电荷泵设置
	SSD1306WriteCmd(0x14); //bit2，开启/关闭
	SSD1306WriteCmd(0x20); //设置内存地址模式
	SSD1306WriteCmd(0x00); //[1:0],00，列地址模式;01，行地址模式;10,页地址模式;默认10;
	
	SSD1306WriteCmd(0xA1); //段重定义设置,bit0:0,0->0;1,0->127;
	SSD1306WriteCmd(0xC0); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
	SSD1306WriteCmd(0xDA); //设置COM硬件引脚配置
	SSD1306WriteCmd(0x12); //[5:4]配置
		 
	SSD1306WriteCmd(0x81); //对比度设置
	SSD1306WriteCmd(0xEF); //1~255;默认0X7F (亮度设置,越大越亮)
	SSD1306WriteCmd(0xD9); //设置预充电周期
	SSD1306WriteCmd(0xf1); //[3:0],PHASE 1;[7:4],PHASE 2;
	SSD1306WriteCmd(0xDB); //设置VCOMH 电压倍率
	SSD1306WriteCmd(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

	SSD1306WriteCmd(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
	SSD1306WriteCmd(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示	    						   
	SSD1306WriteCmd(0xAF); //开启显示
}
